#include "stdafx.h"
#include "SomeContainer.h"
#include "IObject.h"
#include "SomeContainterIterator.h"

CSomeContainer::CSomeContainer()
: m_head(NULL)
, m_toBeDeleted(NULL)
, m_threadInPop(0)
, m_size(0)
{
}

CSomeContainer::~CSomeContainer()
{
    if (m_head.load() != NULL)
    {
        TryReclaim(m_head.load());
    }
}

bool CSomeContainer::Register(int objectId, boost::shared_ptr<IObject> object)
{
    if (Query(objectId) != NULL)
    {
        return false;
    }

    Node* newNode = NULL;
    Node* left = NULL;
    do
    {
        newNode = new Node(object, objectId, m_head.load());
        left = newNode->next;
    } while(!m_head.compare_exchange_weak(left, newNode));

    ++m_size;
    return true;
}

bool CSomeContainer::Unregister(int objectId)
{
    if (m_head.load() == NULL)
    {
        return false;
    }

    ++m_threadInPop;
    Node* oldHead = m_head.load();
    if (m_head.load()->index == objectId)
    {
        oldHead = m_head.load();
    }
    else
    {
        while (oldHead && oldHead->next && oldHead->next->next && oldHead->next->index != objectId)
        {
            oldHead = oldHead->next;
        }
        if (oldHead && oldHead->next && oldHead->next->index != objectId)
        {
            --m_threadInPop;
            return false;
        }
    }
    
    Node* toDelete;
    if (oldHead->next && oldHead->index != objectId)
    {
        toDelete = oldHead->next;
        boost::atomic<Node*> oldHeadAtomic(oldHead->next->next);

        while(oldHead && oldHead->next && !oldHeadAtomic.compare_exchange_weak(oldHead->next, oldHead->next->next));
    }
    else if(m_head.load() == oldHead && m_head.load()->index == objectId)
    {
        toDelete = oldHead;
        while(oldHead && !m_head.compare_exchange_strong(oldHead, oldHead->next));
    }
    else
    {
        toDelete = oldHead;
        boost::atomic<Node*> oldHead_atomic(oldHead->next);
        while(oldHead && !oldHead_atomic.compare_exchange_strong(oldHead, oldHead->next));
    }
    
    TryReclaim(toDelete);

    return true;
}

boost::shared_ptr<IObject> CSomeContainer::Query(int objectId)
{
    Node* oldHead = m_head.load();
    while (oldHead)
    {
        if (oldHead->index == objectId)
        {
            return oldHead->data;
        }
        oldHead = oldHead->next;
    }
    
    IObject* p = NULL;
    return boost::shared_ptr<IObject>(p);
}

std::auto_ptr<ISomeContainterIterator> CSomeContainer::CreateIterator()
{
    return std::auto_ptr<ISomeContainterIterator>(new CSomeContainterIterator(this));
}

void CSomeContainer::ChainNodeList(Node* first, Node* last)
{
    last->next = m_toBeDeleted;
    while (!m_toBeDeleted.compare_exchange_weak(last->next, first));
}

void CSomeContainer::ChainNodeList(Node* nodes)
{
    Node* last = nodes;
    while(Node* next = last->next)
    {
        last = next;
    }
    ChainPendingNodes(nodes, last);
}

void CSomeContainer::ChainOneNode(Node* node)
{
    ChainPendingNodes(node, node);
}

void CSomeContainer::ChainPendingNodes(Node* first, Node* last)
{
    last->next = m_toBeDeleted;
    while(!m_toBeDeleted.compare_exchange_weak(last->next, first));
}

void CSomeContainer::DeleteNodes(Node* nodes)
{
    while(nodes)
    {
        Node* next = nodes->next;
        delete nodes;
        nodes = next;
    }
}

void CSomeContainer::TryReclaim(Node* oldHead)
{
    if(m_threadInPop == 1)
    {
        Node* nodesToDelete = m_toBeDeleted.exchange(NULL);
        if(!--m_threadInPop)
        {
            DeleteNodes(nodesToDelete);
        }
        else if(nodesToDelete)
        {
            ChainNodeList(nodesToDelete);
        }
        delete oldHead;
        if (--m_size == 0)
        {
            m_head.store(NULL);
        }
    }
    else
    {
        ChainOneNode(oldHead);
        --m_threadInPop;
    }
}